package liming.tool.lock;

import liming.tool.lock.CodeLock;
import liming.tool.runnable.HaveReturnValueInterface;

import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;

public class CodeCondition {
    private final Condition condition;
    private final CodeLock lock;

    CodeCondition(CodeLock codeLock, Condition condition) {
        this.lock = codeLock;
        this.condition = condition;
    }

    public Type await() {
        return lock.lock(new HaveReturnValueInterface<Type>() {
            @Override
            public Type run() throws Exception {
                condition.await();
                return Type.NORMAL;
            }

            @Override
            public Type onException(Exception e) {
                return Type.INTERRUPT;
            }
        });
    }

    public void awaitUninterruptibly() {
        lock.lock(condition::awaitUninterruptibly);
    }

    public Type await(long time, TimeUnit unit) {
        return lock.lock(new HaveReturnValueInterface<Type>() {
            @Override
            public Type run() throws Exception {
                if (condition.await(time, unit))
                    return Type.TIMEOUT;
                return Type.NORMAL;
            }

            @Override
            public Type onException(Exception e) {
                return Type.INTERRUPT;
            }
        });
    }

    public Type awaitUntil(Date deadline) {
        return lock.lock(new HaveReturnValueInterface<Type>() {
            @Override
            public Type run() throws Exception {
                return condition.awaitUntil(deadline)? Type.NORMAL : Type.TIMEOUT;
            }

            @Override
            public Type onException(Exception e) {
                return Type.INTERRUPT;
            }
        });
    }

    public long awaitNanos(long nanosTimeout) {
        return lock.lock(new HaveReturnValueInterface<Long>() {
            @Override
            public Long run() throws Exception {
                return condition.awaitNanos(nanosTimeout);
            }

            @Override
            public Long onException(Exception e) {
                return 0L;
            }
        });
    }

    public void signal() {
        lock.lock(condition::signal);
    }

    public void signalAll() {
        lock.lock(condition::signalAll);
    }


    /**
     * NORMAL 正常
     * INTERRUPT 中断
     * TIMEOUT 超时
     */
    public enum Type {//正常，中断,超时
        NORMAL,
        INTERRUPT,
        TIMEOUT
    }
}
